/******************************************************************************
 * Copyright (C) 2024 EternalChip, Inc.(Gmbh) or its affiliates.
 * 
 * All Rights Reserved.
 * 
 * @file key.c
 * 
 * @par dependencies 
 * - bsp_key.h
 * - stdio.h
 * - stdint.h
 * 
 * @author Jack | R&D Dept. | EternalChip ��оǶ��ʽ
 * 
 * @brief Provide the HAL APIs of Key and corresponding opetions.
 * 
 * Processing flow:
 * 
 * call directly.
 * 
 * @version V1.0 2024-10-30
 *
 * @note 1 tab == 4 spaces!
 * 
 *****************************************************************************/

#include "bsp_key_irq.h"


#define FALLING_TYPE 0
#define RAISING_TYPE 1

osThreadId_t key_TaskHandle;




QueueHandle_t key_queue = NULL;
QueueHandle_t inter_key_queue = NULL;

const osThreadAttr_t key_Task_attributes = {
  .name = "key_Task",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};



key_status_t key_scan(key_press_status_t * key_value)
{
    
    uint32_t counter = 0;
    key_press_status_t key_status_value = KEY_NOT_PRESSED;
    
    while (counter < 1000){
        
        if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET)
        {
            key_status_value = KEY_PRESSED;
            *key_value = key_status_value;
            return KEY_OK;
        }
        //2.2 �������û�б�����
        counter++;
    }
    *key_value = key_status_value;
    
    return KEY_ERRORTIMEOUT;//ʼ��û�а��������£����س�ʱ
}

key_status_t key_scan_short_long_press(key_press_status_t * key_value,
                                       uint32_t short_press_time)
{
    /**Variables** */
    key_status_t ret_key_status       = KEY_OK;
    key_press_status_t key_value_temp = KEY_NOT_PRESSED;
    uint32_t count_tick               = 0;
    /**Variables** */

    //1.check if the key is pressed
    ret_key_status = key_scan(&key_value_temp);
    //1.1 if the key is pressed,then check if it is short pressed
    if(KEY_OK == ret_key_status)
    {
        if(key_value_temp == KEY_PRESSED)
        {
            count_tick = HAL_GetTick();
            //1.1.1 check the short press time 
            while(HAL_GetTick() < count_tick + short_press_time)
            ;
            ret_key_status = key_scan(&key_value_temp);
						
            if(KEY_NOT_PRESSED == key_value_temp)
            {
                * key_value = KEY_SHORT_PRESSED;              
                return KEY_OK;
            }
            else
            {
                * key_value = KEY_LONG_PRESSED;
							
							//1.1.2.1keep focuing on the status of key to avoid the short
							while(KEY_OK == key_scan(&key_value_temp))
								;
                 return KEY_OK;
            }
            
        }
    }
    return ret_key_status;
}

void key_task_func(void *argument)
{
    /** Variables(in task stack)   **/

	key_press_event_t key_press_event =                {.edge_type = RASING,
	                                                      .trigger_tick = 0};
	uint32_t event_index              =                  0;
	uint32_t first_trigger_tick       =                  0;
	uint32_t short_press_time         =        SHORT_PRESS_TIME;
	/** Variables(in task stack)   **/
	
	 /** Variables(in OS heap)   **/
  key_queue       = xQueueCreate( 10, sizeof( key_press_status_t ) );
	
	inter_key_queue = xQueueCreate( 10, sizeof( key_press_event_t ) );
	/** Variables(in OS heap)   **/
	
  
  if (NULL == key_queue || NULL == inter_key_queue)
  {
      printf("key_queue created failed \r\n");
		  return;
  } 
  else
  {
      printf("key_queue created successfully \r\n");
  }
  for(;;)
  {
		
		 printf("key_task_func running " 
		          "at [%d] tick\r\n",HAL_GetTick());
    if( pdTRUE == xQueueReceive( inter_key_queue, &( key_press_event ), ( TickType_t ) 0) )
    {
			
			printf("key_press_event.trigger_tick = [%d]r\n",
			                                key_press_event.trigger_tick  );
			printf("inter_key_queue receive key event"
			                     " at [%d] tick\r\n",HAL_GetTick());
			
			if(RASING == key_press_event.edge_type &&
             0  ==               event_index )
			{
				printf("KEY RASING FETCHED,ERROR\r\n");
				
			}
			if(FALLING == key_press_event.edge_type &&
             0  ==               event_index )
			{
				printf("key falling fetched first\r\n");
				event_index += 1;
				
				first_trigger_tick = key_press_event.trigger_tick;
			}
			if(RASING == key_press_event.edge_type &&
						 1  ==               event_index )
				{
					printf("key rasing after the falling\r\n");
					if(key_press_event.trigger_tick - first_trigger_tick < 10)
					{
						printf("Invalid key fetched");
					  continue;
					}
					if(key_press_event.trigger_tick - first_trigger_tick 
						                                               < short_press_time)
					{
						key_press_status_t key_result = KEY_SHORT_PRESSED;
						if ( pdTRUE == xQueueSendToFront(       key_queue,
							                                    &key_result,
						                                                0))
            {
                printf(" send short press successfully at [%d] tick\r\n",
																												HAL_GetTick());
							
								event_index = 0;
					  }
						else
						{
								printf(" send short press fail at [%d] tick\r\n",
																														HAL_GetTick());
						}
					}	
						if(key_press_event.trigger_tick - first_trigger_tick 
						                                               > short_press_time)
					 {
						key_press_status_t key_result = KEY_LONG_PRESSED;
						if ( pdTRUE == xQueueSendToFront(       key_queue,
							                                    &key_result,
						                                                0))
            {
                printf("send long press successfully at [%d] tick\r\n",
																												HAL_GetTick());
								event_index = 0;
					  }
						else
						{
								printf(" send long press fail at [%d] tick\r\n",
																														HAL_GetTick());
						}
				   }
		
		      
    
    
							
						}
				} 
		osDelay(100);
  }
}
  /* USER CODE END 5 */

/**
 * @brief key_interuption_callback.
 * 
 * Steps:
 *  1. if trigger first time with falling type,\
       send the event to the inter_key_queue  \
       changeing the interruption type to Raising
 *  
		2. if trigger first time with Raising type,\
       send the event to the inter_key_queue  \
       changeing the interruption type back to falling
 * @param[in] void
 * 
 * @return void
 * 
 * */
KEY_CALLBACK
{
#if 1
	  static uint32_t irq_type = FALLING_TYPE;
	
	
		BaseType_t xHigherPrioritTaskWoken;
	  
	
	if( FALLING_TYPE == irq_type )
	{
			key_press_event_t key_press_event_1 =
			{
				.edge_type = FALLING,
				.trigger_tick = HAL_GetTick()
			
			};
			
			if( NULL == inter_key_queue )
			{
//				printf("inter_key_queue creat fail at [%d] tick\r\n",
//																										HAL_GetTick());
			}
			
			if ( pdTRUE ==  xQueueSendToFrontFromISR(  inter_key_queue, 
																							 &key_press_event_1, 
																					&xHigherPrioritTaskWoken ))
			{
//					printf("key_result send falling successfully at [%d] tick\r\n",
//																									HAL_GetTick());
			}
			
				//change the irq_type
				irq_type = RAISING_TYPE;
				
				GPIO_InitTypeDef GPIO_InitStruct = {0};
				
				GPIO_InitStruct.Pin = KEY_Pin;
				GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
				GPIO_InitStruct.Pull = GPIO_PULLUP;
				HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStruct);
	}
	else if(RAISING_TYPE == irq_type)
	{
			key_press_event_t key_press_event_2 =
		{
			.edge_type = RASING,
			.trigger_tick = HAL_GetTick()
		
		};
		
		if(NULL == inter_key_queue)
		{
//			printf("inter_key_queue creat fail at [%d] tick\r\n",
//																									HAL_GetTick());
		}
		
		if ( pdTRUE ==  xQueueSendToFrontFromISR(        inter_key_queue, 
																										&key_press_event_2, 
																							&xHigherPrioritTaskWoken ))
		{
//				printf("key_result send raising successfully at [%d] tick\r\n",
//																								HAL_GetTick());
		}
		
		//change the irq_type
		irq_type = FALLING_TYPE;
		
		GPIO_InitTypeDef GPIO_InitStruct = {0};
		
		GPIO_InitStruct.Pin = KEY_Pin;
		GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStruct);
	}
#endif
#if 0
	 static uint32_t irq_type = FALLING_TYPE;
   /*
    1.if trigger first time with falling type,\
      send the event to the inter_key_queue \
      changing the interruption type to Raising
    */
    BaseType_t xHigherPrioritTaskWoken;
    
    if ( FALLING_TYPE == irq_type )
    {
        key_press_event_t key_press_event_1 = 
        {
            .edge_type    = FALLING,
            .trigger_tick = HAL_GetTick()
        };
        
        if ( NULL == inter_key_queue )
        {
            printf( "inter_key_queue not created"
                    " at [%d] tick \r\n", 
                                   HAL_GetTick());
        }        

        if ( pdTRUE == xQueueSendToFrontFromISR(            inter_key_queue, 
                                                         &key_press_event_1, 
                                                    &xHigherPrioritTaskWoken ))
        {
            printf( "key_press_event send FALING_event successfully"
                    " at [%d] tick \r\n", 
                                   HAL_GetTick());
        }
    /*
    1.1 changing the irq type
    */
        irq_type = RAISING_TYPE;
    /*
    1.2 changing the GPIO irq trigger type
    */ 
        GPIO_InitTypeDef GPIO_InitStruct = {0};
            
        GPIO_InitStruct.Pin = KEY_Pin;
        GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStruct);
    }
    else if ( RAISING_TYPE == irq_type )
    {
            
    /*  
    2.if trigger first time with Raising type,\
      send the event to the inter_key_queue \
      changing the interruption type back to falling
    */
         key_press_event_t key_press_event_2 = 
        {
            .edge_type    = RASING,
            .trigger_tick = HAL_GetTick()
        };
    
        if ( NULL == inter_key_queue )
        {
            printf( "inter_key_queue not created"
                    " at [%d] tick \r\n", 
                                   HAL_GetTick());
        }        
        if ( pdTRUE == xQueueSendToFrontFromISR(              inter_key_queue, 
                                                           &key_press_event_2, 
                                                     &xHigherPrioritTaskWoken ))
        {
            printf( "key_press_event send RASING_event successfully"
                    " at [%d] tick \r\n", 
                                   HAL_GetTick());
        }
        
    /*
    1.1 changing the irq type
    */
        irq_type = FALLING_TYPE;
    /*
    1.2 changing the GPIO irq trigger type
    */ 
        GPIO_InitTypeDef GPIO_InitStruct = {0};
            
        GPIO_InitStruct.Pin = KEY_Pin;
        GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStruct);
    }
#endif
}

     



















